/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include <vulkan/vulkan.h>
#include "向量.h"

#include "Vk缓存.h"

#include "../Core/Vk结构声明.h"
#include "底层绘图/S_纹理.h"


#include "S_键值序列容器.h"



void f_vkImage_setLayout(VkCommandBuffer cmd, VkImage image,
	VkImageAspectFlags aspectMask,
	VkImageLayout old_image_layout,
	VkImageLayout new_image_layout,
	int32  layerCount,
	int32  baseArrayLayer = 0,
	uint32 mipCount = 1
);

void f_vkImage_着色器读写布局(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, int32 layerCount, int32 baseArrayLayer = 0);
void f_vkImage_帧缓存布局(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, int32 layerCount, int32 baseArrayLayer = 0);


VkImageUsageFlags f_get纹理用途(E_纹理用途 用途);

inline VkImageType f_转VK纹理类型(E_纹理维度类型 type) {
	switch (type) {
		case E_纹理维度类型::e_1D: return VK_IMAGE_TYPE_1D;
		case E_纹理维度类型::e_2D: return VK_IMAGE_TYPE_2D;
		case E_纹理维度类型::e_3D: return VK_IMAGE_TYPE_3D;

		case E_纹理维度类型::e_CUBE:
		case E_纹理维度类型::e_CUBE_Array:
			return VK_IMAGE_TYPE_2D;
		default:
			break;
	}

	return VK_IMAGE_TYPE_2D;
}

inline VkImageViewType f_转VK纹理视图类型(E_纹理维度类型 type) {
	switch (type) {
		case E_纹理维度类型::e_1D: return VK_IMAGE_VIEW_TYPE_1D;
		case E_纹理维度类型::e_2D: return VK_IMAGE_VIEW_TYPE_2D;
		case E_纹理维度类型::e_3D: return VK_IMAGE_VIEW_TYPE_3D;
		case E_纹理维度类型::e_2D_Array: return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
		case E_纹理维度类型::e_CUBE: return VK_IMAGE_VIEW_TYPE_CUBE;
		case E_纹理维度类型::e_CUBE_Array: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
		default:
			break;
	}
	return VK_IMAGE_VIEW_TYPE_2D;
}

inline VkFormat f_vk_getVK图像格式(const E_纹理格式& 格式) {
	switch (格式) {
	case e_tf_R8:			return VK_FORMAT_R8_SINT;
	case e_tf_RG8:			return VK_FORMAT_R8G8_SINT;
	case e_tf_RGB8:			return VK_FORMAT_R8G8B8_SINT;
	case e_tf_RGBA8:		return VK_FORMAT_R8G8B8A8_SINT;

	case e_tf_R16:			return VK_FORMAT_R16_SINT;
	case e_tf_RG16:			return VK_FORMAT_R16G16_SINT;
	case e_tf_RGB16:		return VK_FORMAT_R16G16B16_SINT;
	case e_tf_RGBA16:		return VK_FORMAT_R16G16B16A16_SINT;

	case e_tf_R32:			return VK_FORMAT_R32_SFLOAT;
	case e_tf_RG32:			return VK_FORMAT_R32G32_SFLOAT;
	case e_tf_RGB32:		return VK_FORMAT_R32G32B32_SFLOAT;
	case e_tf_RGBA32:		return VK_FORMAT_R32G32B32A32_SFLOAT;





	case e_tf_R8U_归一化:		return VK_FORMAT_R8_UNORM;
	case e_tf_RG8U_归一化:		return VK_FORMAT_R8G8_UNORM;
	case e_tf_RGB8U_归一化:		return VK_FORMAT_R8G8B8_UNORM;
	case e_tf_RGBA8U_归一化:	return VK_FORMAT_R8G8B8A8_UNORM;

	case e_tf_R8U:			return VK_FORMAT_R8_UINT;
	case e_tf_RG8U:			return VK_FORMAT_R8G8_UINT;
	case e_tf_RGB8U:		return VK_FORMAT_R8G8B8_UINT;
	case e_tf_RGBA8U:		return VK_FORMAT_R8G8B8A8_UINT;



	case e_tf_R16U:			return VK_FORMAT_R16_UINT;
	case e_tf_RG16U:		return VK_FORMAT_R16G16_UINT;
	case e_tf_RGB16U:		return VK_FORMAT_R16G16B16_UINT;
	case e_tf_RGBA16U:		return VK_FORMAT_R16G16B16A16_UINT;

	case e_tf_R32U:			return VK_FORMAT_R32_UINT;
	case e_tf_RG32U:		return VK_FORMAT_R32G32_UINT;
	case e_tf_RGB32U:		return VK_FORMAT_R32G32B32_UINT;
	case e_tf_RGBA32U:		return VK_FORMAT_R32G32B32A32_UINT;

	//case e_tf_R32U_U:		return VK_FORMAT_R32_UINT;
	//case e_tf_RG32U_U:		return VK_FORMAT_R32G32_UINT;
	//case e_tf_RGB32U_U:		return VK_FORMAT_R32G32B32_UINT;
	//case e_tf_RGBA32U_U:	return VK_FORMAT_R32G32B32A32_UINT;

	//e_tf_深度纹理:



	case e_tf_D16:			return VK_FORMAT_D16_UNORM_S8_UINT;
	case e_tf_D24:			return VK_FORMAT_D24_UNORM_S8_UINT;
	case e_tf_D32:			return VK_FORMAT_D32_SFLOAT_S8_UINT;
	case e_tf_D64:			return VK_FORMAT_D32_SFLOAT_S8_UINT;
	case e_tf_D32F:			return VK_FORMAT_D32_SFLOAT;
	default:
		break;
	}

	return VK_FORMAT_UNDEFINED;
}




struct S_Vk图像管理 {
	

	~S_Vk图像管理();

	static void			f_释放图像(VkDevice& dev, S_VkImage* image);

	static S_VkImage*	f_创建图像视图(VkDevice& dev, VkImage image, const VkFormat& 格式, uint32 布局);

	static S_VkImage*	f_创建纹理图像(S_设备环境& ctx, const VkFormat& 格式, uvec3 size, E_纹理维度类型 类型, uint32 用途, E_MS次数 采样 = E_MS次数::e_MS_1, uint32 key = 0);

	static S_VkImage*	f_创建帧缓存图像(VkDevice& dev, VkPhysicalDeviceMemoryProperties 内存属性, VkFormat 格式, E_纹理维度类型 类型, uvec3 size, E_MS次数 采样, uint32 key = 0, uint32 层 = 1);

	static S_VkImage*	f_创建深度缓存图像(VkDevice& dev
											, VkPhysicalDeviceMemoryProperties 内存属性
											, VkPhysicalDeviceProperties 物理设备属性
											, VkFormat f
											, uvec3 size
											, E_MS次数 采样
											, E_纹理维度类型 类型 = E_纹理维度类型::e_2D);

	
};



VkFormat findSupportedFormat(const VkPhysicalDevice phyDev, 
							const vector<VkFormat>& candidates, 
							VkImageTiling tiling, 
							VkFormatFeatureFlags features);

VkFormat f_findDepthFormat(const VkPhysicalDevice phyDev);


void					f_VkImage_构建(S_VkImage* obj, S_设备环境& ctx);
VkImageMemoryBarrier	f_vk_图像屏障();

void f_releaseImage(VkDevice dev, S_VkImage* obj);



struct S_Vk纹理采样器 : public S_纹理采样器 {
	VkSampler	m_采样器;

	S_Vk纹理采样器(VkDevice& dev, S_纹理采样器创建参数 参数);
	~S_Vk纹理采样器();
};



VkImage f_tex_创建图像(VkDevice& dev, VkFormat 格式, E_纹理维度类型 类型, uvec3 size, uint32 用途, E_MS次数 采样, uint32 mip = 1);

void f_tex_分配图像内存(S_设备环境& ctx, S_VkImage& image);

void f_tex_创建图像视图(VkDevice& dev, S_VkImage& image, VkImageAspectFlagBits ImageAspect, VkFormat 格式, E_纹理维度类型 类型, uint32 层数量, uint32 布局);

void f_tex_销毁图像视图(VkDevice& dev, S_VkImage& image);




Inline void f_纹理槽_设置GPU参数(const S_GPU纹理参数槽& 纹理槽, VkWriteDescriptorSet& writes, VkDescriptorSet set, int32 i) {
	writes.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
	writes.pNext = nullptr;
	writes.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
	writes.pImageInfo = (VkDescriptorImageInfo*)纹理槽.m_纹理信息[i];
	writes.descriptorCount = 纹理槽.m_绑定数量[i];
	writes.dstBinding = 纹理槽.m_绑定位置[i];
	writes.dstSet = set;
	writes.dstArrayElement = 0;
}


Inline void f_纹理槽_设置纹理读写(const S_GPU纹理参数槽& 纹理槽, VkWriteDescriptorSet& writes, VkDescriptorSet set, int32 i) {
	writes.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
	writes.pNext = nullptr;
	writes.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
	writes.pImageInfo = (VkDescriptorImageInfo*)纹理槽.m_纹理信息[i];
	writes.descriptorCount = 纹理槽.m_绑定数量[i];
	writes.dstBinding = 纹理槽.m_绑定位置[i];
	writes.dstSet = set;
	writes.dstArrayElement = 0;
}



